aboutsummaryrefslogtreecommitdiff
path: root/src/routes/grocery/[id]/+page.server.ts
diff options
context:
space:
mode:
authorMartin Kagamino Lehoux <martin@lehoux.net>2026-07-28 15:07:57 +0200
committerMartin Kagamino Lehoux <martin@lehoux.net>2026-07-28 15:07:57 +0200
commit04fabf115ccea31ac504b06cc51d78423b697f60 (patch)
tree26c21f8822ccd24fce3a80b7361382c8a87d0c96 /src/routes/grocery/[id]/+page.server.ts
parent45cc0afb734a422ee7765dc5c60dccbcc6721367 (diff)
refactor: services layer, valibot validation, shared CSS utilities, aria labels, and drizzle migrate
- Extract groceries/categories/references services with db injection - Add valibot for form validation and safe numeric id parsing - Fix category delete FK behavior with onDelete: set null + migration - Replace custom migrate.js with drizzle-orm/libsql/migrator - Add shared CSS utility classes in app.css (forms, lists, buttons) - Add aria-pressed and aria-label on interactive elements - Remove redundant app.css imports and unused /stores import - Add integration tests for all services using drizzle migrate helper - Remove smoke test; add db:migrate and db:studio scripts
Diffstat (limited to 'src/routes/grocery/[id]/+page.server.ts')
-rw-r--r--src/routes/grocery/[id]/+page.server.ts58
1 files changed, 34 insertions, 24 deletions
diff --git a/src/routes/grocery/[id]/+page.server.ts b/src/routes/grocery/[id]/+page.server.ts
index b19825a..3c3967a 100644
--- a/src/routes/grocery/[id]/+page.server.ts
+++ b/src/routes/grocery/[id]/+page.server.ts
@@ -1,11 +1,28 @@
import { error, fail, redirect } from '@sveltejs/kit';
import { db } from '$lib/server/db';
-import { groceries, categories, references } from '$lib/server/db/schema';
+import { groceries, categories } from '$lib/server/db/schema';
import { eq } from 'drizzle-orm';
+import {
+ loadForGrocery,
+ add as addRef,
+ deleteReference,
+} from '$lib/server/services/references';
+import { deleteGrocery } from '$lib/server/services/groceries';
+import {
+ numericId,
+ parseFormString,
+ parseOptionalNumber,
+} from '$lib/server/services/validation';
+import type { Grocery, Reference } from '$lib/server/services/types';
import type { Actions, PageServerLoad } from './$types';
+export interface GroceryDetailOutput {
+ item: Grocery & { categoryName: string | null };
+ references: Reference[];
+}
+
export const load: PageServerLoad = async ({ params }) => {
- const id = Number(params.id);
+ const id = numericId(params.id);
const [item] = await db.select().from(groceries).where(eq(groceries.id, id));
if (!item) throw error(404, 'Article introuvable');
@@ -17,10 +34,7 @@ export const load: PageServerLoad = async ({ params }) => {
.where(eq(categories.id, item.categoryId))
: [null];
- const refs = await db
- .select()
- .from(references)
- .where(eq(references.groceryId, id));
+ const refs = await loadForGrocery(id);
return {
item: {
@@ -34,38 +48,34 @@ export const load: PageServerLoad = async ({ params }) => {
export const actions: Actions = {
add: async ({ request, params }) => {
const data = await request.formData();
- const reference = data.get('reference')?.toString().trim();
- const price = data.get('price')?.toString().trim();
- const unit = data.get('unit')?.toString().trim();
- const qualityScore = data.get('quality_score')?.toString().trim();
+ const groceryId = numericId(params.id);
+ const reference = parseFormString(data.get('reference'));
+ const price = parseOptionalNumber(data.get('price'));
+ const unit = parseFormString(data.get('unit'));
+ const qualityScore = parseOptionalNumber(data.get('quality_score'));
if (!reference) {
return fail(400, { error: 'La référence est requise' });
}
- await db.insert(references).values({
- groceryId: Number(params.id),
- reference,
- price: price ? Number(price) : null,
- unit: unit || null,
- qualityScore: qualityScore ? Number(qualityScore) : null,
- });
-
+ await addRef(groceryId, reference, price, unit, qualityScore);
return { success: true };
},
delete: async ({ request }) => {
const data = await request.formData();
- const id = Number(data.get('id'));
-
- await db.delete(references).where(eq(references.id, id));
-
+ try {
+ const id = numericId(data.get('id'));
+ await deleteReference(id);
+ } catch {
+ return fail(400, { error: 'ID invalide' });
+ }
return { success: true };
},
deleteItem: async ({ params }) => {
- await db.delete(groceries).where(eq(groceries.id, Number(params.id)));
-
+ const groceryId = numericId(params.id);
+ await deleteGrocery(groceryId);
throw redirect(303, '/');
},
};